#! /usr/bin/env python
#                   _ooOoo_                     
#                  o8888888o                    
#                  88" . "88                    
#                  (| -_- |)                    
#                  O\  =  /O                    
#               ____/`---'\____                 
#             .'  \\|     |//  `.               
#            /  \\|||  :  |||//  \              
#           /  _||||| -:- |||||-  \             
#           |   | \\\  -  /// |   |             
#           | \_|  \---/  |   |             
#           \  .-\__  `-`  ___/-. /             
#         ___`. .'  /--.--\  `. . __            
#      ."" '<  `.___\_<|>_/___.'  >'"".      
#     | | :  `- \`.;`\ _ /`;.`/ - ` : | |       
#     \  \ `-.   \_ __\ /__ _/   .-` /  /       
#======`-.____`-.___\_____/___.-`____.-'======  
#                   `=---='                     
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  
#         Buddha bless me for no bug            
#                                               
####################################################################################
#   Filename    :  StarTdef.py                                                      
#   Author      :  Shawn Tan                                                        
#   Date        :  2017.1.8                                                        
#   Description :  the Tdef parser module for runsim                                                                   
#   History     :  2017.1.8             creat the document            Shawn Tan    
####################################################################################

__author__='ST-Cat'

import time
import copy
import os
from StarRE      import *
from StarVar     import *
from StarInfo    import *
from StarThread  import *
from StarEda     import *

#########################################################################################
#                                     Parser  
#########################################################################################

########################################################################
#                            Date Base Solver
########################################################################

def solve_comment(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE):
  '''solve comment line'''
  pass

def solve_tdef_attr(line, TYPE=ATTRIBUTE):

  '''unify function to solve tdef attr'''
  
  o = TYPE()

  if '+=' in line:
    assert line.count('+=') == 1, tdef020+line 
    assert attribute_keyword[line.split('+=')[0].strip()],tdef021+line
    o.name=line.split('+=')[0].strip()
    o.value=line.split('+=')[1].strip()
    o.type=attribute_type[line.split('+=')[0].strip()]
    o.attr='add'
  elif '-=' in line:
    assert line.count('-=') == 1, tdef022+line
    assert attribute_keyword[line.split('-=')[0].strip()],tdef021+line
    o.name=line.split('-=')[0].strip()
    o.value=line.split('-=')[1].strip()
    o.type=attribute_type[line.split('-=')[0].strip()]
    o.attr='remove'
  elif '*=' in line:
    assert line.count('*=') == 1, tdef022+line
    assert attribute_keyword[line.split('*=')[0].strip()],tdef021+line
    o.name=line.split('*=')[0].strip()
    o.value=line.split('*=')[1].strip()
    o.type=attribute_type[line.split('*=')[0].strip()]
    o.attr='override'
  else: 
    assert attribute_keyword[line.split('=', 1)[0].strip()], tdef021+line
    o.name=line.split('=', 1)[0].strip()
    o.value=line.split('=',1)[1].strip()
    o.type=attribute_type[line.split('=', 1)[0].strip()]
    o.attr='assign'



  return o

def solve_group_extends(s, name, line, TYPE=GROUP):
  '''solve the group extends operation'''

  o=TYPE()
  o.name=name['group']

  if hasattr(o, 'num'):
    pass
  else:
    setattr(o, 'num', 0)

  # extends check
  if ('(' in line) and (')' in line): 
    assert extends_re.search(line), tdef025+line 
    extends_m = extends_re.search(line)
    extends_list = extends_m.group() 
    extends = ''.join(extends_list.split()).split(',')

    for i in extends:
      assert i in s.groups.keys(), tdef026+' Parent Group : '+i+' Sub Group : '+name['group']+' Session : '+s.name

      if not hasattr(o, "attributes"):
        o.attributes = []
      if not hasattr(o, "tests"):
        o.tests = {}

      for attr in s.groups[i].attributes: 
        o.attributes.append(attr)

      for tst in s.groups[i].tests:
        for ts in o.tests: 
          assert ts != tst, tdef027+' Group : '+o.name+' Test : '+tst.name 
        o.tests[tst]=copy.deepcopy(s.groups[i].tests[tst])

      o.num += s.groups[i].num

    for i in o.tests: 
      path = [s.name, name['group'], i]
      s.testpath[i].append(path)

  return o


def solve_session_head(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE):
  '''build a session node'''
  #print name['session']
  setattr(s, 'name', name['session'])

  setattr(s, 'num', 0)

  s.testpath={} 

def solve_session_attr(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE):
  '''add sesssion attr element'''

  line=line.strip()

  if hasattr(s, 'attributes'):
    pass
  else:
    s.attributes=[]

  if hasattr(s, 'num'):
    pass
  else:
    setattr(s, 'num', 0)

  attr=solve_tdef_attr(line, TYPE2)

  assert attr.name not in attr_only_in_test, tdef038+attr.name 

  s.attributes.append(attr)

def solve_group_head(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE):
  '''build a group node'''

  line=line.strip()

  if hasattr(s, 'groups'):
    assert not s.groups.has_key(name['group']), tdef024+str(name['group'])+' in session :'+str(name['session'])  
  else:
    s.groups={}

  s.groups[name['group']]=copy.deepcopy(solve_group_extends(s, name, line, TYPE=GROUP))

def solve_group_test_head(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE):
  line=line.strip()

  o=s.groups[name['group']]

  if hasattr(o, 'tests'):

    assert not o.tests.has_key(name['test']), tdef023+'Group : '+name['group']+' Test : '+name['test'] \
          +'Session :'+name['session']  
  else:
    o.tests={}

  if hasattr(o, 'num'):
    o.num+=1
  else:
    setattr(o, 'num', 0)

  k=TYPE1()

  k.name=name['test']

  assert name['test'] not in s.groups, tdef031+name['test']

  path=[s.name, o.name, name['test']]

  if not s.testpath.has_key(name['test']):
    s.testpath[name['test']] = []

  s.testpath[name['test']].append(path)

  o.tests[name['test']]=copy.deepcopy(k)

def solve_group_test_attr(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE):
   
  o=s.groups[name['group']]
  k=o.tests[name['test']]

  if hasattr(k, 'attributes'):
    pass
  else:
    k.attributes=[]

  attr = solve_tdef_attr(line, TYPE2)
  assert attr.name not in attr_not_in_test, tdef039+attr.name  
  k.attributes.append(attr)

  if attr.name == 'category':
    k.category = (hasattr(k, 'category') and k.category != None) and k.category+' '+attr.value or attr.value
  else:
    k.category = hasattr(k, 'category') and k.category or None 

def solve_group_attr(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE):

  o=s.groups[name['group']]

  if hasattr(o, 'attributes'):
    pass
  else:
    o.attributes=[]

  attr=solve_tdef_attr(line, TYPE2)

  assert attr.name not in attr_only_in_test, tdef038+attr.name 

  o.attributes.append(attr)


def solve_test_head(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE):

  line=line.strip()

  if hasattr(s, 'tests'):
    if s.tests.has_key(name['test']):
      setattr(s, 'invalid_name', name['test'])
    assert not s.tests.has_key(name['test']), tdef028+' Test : '+name['test'] + ' Groups : '+name['session']
  else:
    s.tests={}
  
  if hasattr(s, 'num'):
    s.num+=1
  else:
    setattr(s, 'num', 0)

  o=TYPE1()
  o.name=name['test']

  assert name['test'] not in s.groups, tdef031+name['test']

  path=[s.name, 'GROUP', name['test']]

  s.testpath[name].append(path)

  s.tests[name['test']]=copy.deepcopy(o)

def solve_test_attr(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE):

  line=line.strip()

  o=s.tests[name['test']]

  if hasattr(o, 'attributes'):
    pass
  else:
    o.attributes=[]

  attr=solve_tdef_attr(line, TYPE2)

  assert attr.name not in attr_not_in_test, tdef039+attr.name  

  o.attributes.append(attr)

  if attr.name == 'category':
    o.category = (hasattr(o, 'category') and o.category != None) and o.category+' '+attr.value or attr.value
  else:
    o.category = hasattr(o, 'category') and o.category or None 



parser_operation = {
#Operation Type       #Operation Function
'COMMENT'            : lambda option,s,line,name  :  solve_comment(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE), 
'SESSION_HEAD'       : lambda option,s,line,name  :  solve_session_head(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE),
'SESSION_ATTR'       : lambda option,s,line,name  :  solve_session_attr(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE),
'SESSION_TEST_HEAD'  : lambda option,s,line,name  :  solve_test_head(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE),
'SESSION_TEST_ATTR'  : lambda option,s,line,name  :  solve_test_attr(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE),
'GROUP_HEAD'         : lambda option,s,line,name  :  solve_group_head(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE),
'GROUP_TEST_HEAD'    : lambda option,s,line,name  :  solve_group_test_head(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE),
'GROUP_TEST_ATTR'    : lambda option,s,line,name  :  solve_group_test_attr(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE),
'GROUP_ATTR'         : lambda option,s,line,name  :  solve_group_attr(option, s, line, name,  TYPE0=GROUP, TYPE1=TEST, TYPE2=ATTRIBUTE)
}

###########################################################

##################################################
#  get container name 
##################################################

def session_name(line):
  if sessionname.search(line):
    name_m = sessionname.search(line) 
    name = name_m.group()
    return name, True
  else: 
    return None, True

def group_name(line):
  #
  if groupname.search(line):
    name_m = groupname.search(line) 
    name = name_m.group()
    return name, True
  else: 
    return None, True

def test_name(line):
  if testname.search(line):
    name_m = testname.search(line) 
    name = name_m.group()
    return name, True
  else:
    return None, True

get_type_name =  {
#Type      #Operation
'session': lambda line:session_name(line), 
'group'  : lambda line:group_name(line), 
'test'   : lambda line:test_name(line) 
}

###################################################

def remove_space(line):

  "remove the None character from line comment"

  if ' {' in line or ' (' in line:
    input=line.split()
    if '' in input:
      input.remove('')

    output=input[0] 
    for i in range(1, len(input)):
      if '(' not in input[i] and '{' not in input[i]:
        output=output+' '+input[i]
      else: 
        output=output+input[i]

    return output
  else:
    return line

def check_status(line, dict):
  '''check the status of parse operation by current line and return OPCODE'''

  # Comment Judge
  if line.find('#')==0 and line.find('#*')==-1:
    return 'COMMENT'

  elif line.find('#*')==0 and (not '*#' in line):
    dict['COMMENT_NOW'] = True
    dict['COMMENT_NXT'] = Flase
    return 'COMMENT'

  elif line.find('#*')==0 and '*#' in line:
    dict['COMMENT_NOW'] = False
    dict['COMMENT_NXT'] = False
    return 'COMMENT'

  elif dict['COMMENT_NOW'] and not (dict['COMMENT_NXT']) and (not '*#' in line): 
     dict['COMMENT_NOW'] = False
     dict['COMMENT_NXT'] = True
     return 'COMMENT'
  
  elif dict['COMMENT_NOW'] and not (dict['COMMENT_NXT']) and '*#' in line: 
     dict['COMMENT_NOW'] = False
     dict['COMMENT_NXT'] = False
     return 'COMMENT'

  elif not (dict['COMMENT_NOW']) and dict['COMMENT_NXT'] and ('*#' not in line): 
     dict['COMMENT_NOW'] = False
     dict['COMMENT_NXT'] = True
     return 'COMMENT'

  elif not (dict['COMMENT_NOW']) and dict['COMMENT_NXT'] and ('*#' in line): 
     dict['COMMENT_NOW'] = False
     dict['COMMENT_NXT'] = False
     return 'COMMENT'

  elif line.isspace() or line=='':

    if dict['GROUP_NOW']:
      dict['GROUP_NOW'] = False
      dict['GROUP_NXT'] = True
    elif dict['TEST_NOW']:
      dict['TEST_NOW'] = False
      dict['TEST_NXT'] = True
    elif dict['SESSION_NOW']:
      dict['SESSION_NOW'] = False
      dict['SESSION_NXT'] = True

    return 'COMMENT'

  # SESSION Judge
  elif 'session ' in line and line.find('session')==0:
    assert '{' in line, tdef006+line
    assert not (dict['SESSION_NXT'] and dict['SESSION_NOW']), tdef007+line
    assert '}' not in line ,tdef008+line
    assert line.find('session')==0, tdef009+line 

    dict['SessionName'], Flag = get_type_name['session'](line)
    assert Flag, tdef010+line

    dict['SESSION_NOW'] = True
    dict['SESSION_NXT'] = False
    assert sessionname.search(line), tdef010+line
    sessionname_m=sessionname.search(line)
    dict['SessionName'] =  sessionname_m.group()
    return 'SESSION_HEAD'

  elif dict['SESSION_NOW'] and not dict['SESSION_NXT']:   

      dict['SESSION_NOW'] = False
      dict['SESSION_NXT'] = True

      if ('group' not in line) and ('test' not in line):
        return 'SESSION_ATTR'

      elif 'group' in line :
        assert '{' in line, tdef011+line 
        assert '}' not in line, tdef012+line 

        dict['GroupName'], Flag = get_type_name['group'](line)
        assert Flag, tdef013+line

        dict['GROUP_NOW'] = True
        dict['GROUP_NXT'] = False
        return 'GROUP_HEAD'

      elif 'test' in line:
        assert '{' in line, tdef014+line 
        assert '}' not in line, tdef015+line 

        dict['TestName'], Flag = get_type_name['test'](line)
        assert Flag, tdef016+line

        dict['TEST_NOW'] = True
        dict['TEST_NXT'] = False
        return 'SESSION_TEST_HEAD'

  # TEST Judge or GROUP Judge
  elif dict['SESSION_NOW'] or dict['SESSION_NXT']:

    if 'group 'in line:
      assert '{' in line, tdef011+line 
      assert '}' not in line, tdef012+line 

      dict['GroupName'], Flag = get_type_name['group'](line)
      assert Flag, tdef013+line

      dict['GROUP_NOW'] = True
      dict['GROUP_NXT'] = False
      return 'GROUP_HEAD'

    else: 
      # SESSION TEST or ATTR Judge
      if not (dict['GROUP_NOW']) and not (dict['GROUP_NXT']):
        if (not dict['TEST_NOW']) and (not dict['TEST_NXT']):
          if 'test ' in line: 
            assert '{' in line, tdef014+line 
            assert '}' not in line, tdef015+line 
            dict['TEST_NOW'] = True
            dict['TEST_NXT'] = False

            dict['TestName'], Flag = get_type_name['test'](line)
            assert Flag, tdef016+line

            return 'SESSION_TEST_HEAD'
          else:
            if line != '}':
              return 'SESSION_ATTR'
            else: 
              assert not dict['SESSION_NOW'], tdef017+dict['SessionName']
              dict['SESSION_NOW']=False
              dict['SESSION_NXT']=False
              dict['SessionName'] = None
              return 'COMMENT'

        elif dict['TEST_NOW'] or dict['TEST_NXT']:
           assert '{' not in line, tdef014+line
           if '}' in line: 
             assert line == '}', tdef015+line
             if line=='}':
               dict['TEST_NOW'] = False
               dict['TEST_NXT'] = False
               dict['TestName'] = None
               return 'COMMENT'
           else:
             dict['TEST_NOW'] = False
             dict['TEST_NXT'] = True
             return 'SESSION_TEST_ATTR'
      # Group Judge
      elif dict['GROUP_NOW'] or dict['GROUP_NXT']:
        if (not dict['TEST_NOW']) and (not dict['TEST_NXT']):
          if 'test ' in line: 
            assert '{' in line, tdef014+line 
            assert '}' not in line, tdef015+line 
            dict['TEST_NOW'] = True
            dict['TEST_NXT'] = False

            if dict['GROUP_NOW']:
              dict['GROUP_NOW'] = False
              dict['GROUP_NXT'] = True

            dict['TestName'], Flag = get_type_name['test'](line)
            assert Flag, tdef016+line

            return 'GROUP_TEST_HEAD'
          else:
            if line != '}':
              return 'GROUP_ATTR'
            else:
              assert not dict['GROUP_NOW'], tdef017+dict['GroupName'] 
              dict['GROUP_NOW']=False
              dict['GROUP_NXT']=False
              dict['GroupName'] = None
              return 'COMMENT'

        elif dict['TEST_NOW'] or dict['TEST_NXT']:

           if '}' not in line:
             assert '{' not in line, tdef018+line

           if '}' in line and '{' not in line: 
             assert line == '}', tdef015+line
             if line=='}':
               dict['TEST_NOW'] = False
               dict['TEST_NXT'] = False
               dict['TestName'] = None
               return 'COMMENT'
           else:
             dict['TEST_NOW'] = False
             dict['TEST_NXT'] = True
             return 'GROUP_TEST_ATTR'

  else:
    print dict
    assert False,tdef019+line 

def construct_data_structure(option, file, l, TYPE1=SESSION, TYPE2=GROUP, TYPE3=TEST, TYPE4=ATTRIBUTE):
  '''  build tdef data structure'''

  status_dict = {
  #STATUS_NAME      #STATUS
  'COMMENT_NOW'     : False,
  'COMMENT_NXT'     : False,
  'SESSION_NOW'     : False,
  'SESSION_NXT'     : False,
  'GROUP_NOW'       : False,
  'GROUP_NXT'       : False,
  'TEST_NOW'        : False,
  'TEST_NXT'        : False,
  'ATTRIBUTE_NOW'   : False,
  'SessionName'     : None ,
  'GroupName'       : None ,
  'TestName'        : None 
  }

  name_dict = {
  # Name    #Value
  'session' : None,
  'group'   : None,
  'test'    : None
  }
  

  s = TYPE1()
  for line in file:
    #line=line.strip()
    line=' '.join(line.split())
    line=remove_space(line)

    OPCODE = check_status(line, status_dict)

    name_dict['session'] = status_dict['SessionName']
    name_dict['group']   = status_dict['GroupName']
    name_dict['test']    = status_dict['TestName']

    #DebugPP
    if option.Step:
      print line 
      print status_dict
      print OPCODE
    parser_operation[OPCODE](option, s, line, name_dict) 

  tcnum = s.num
  for g in s.groups:
    tcnum+=s.groups[g].num

  setattr(s, 'tcnum', tcnum)

  l.append(s)

def parser_rc_solver(file, lo, RE, Splitor=' '):
  '''get valid tdef info from parser.rc files '''

  for line in file:
    if '//' not in line and '.tdef' in line:
      line=''.join(line.split(Splitor))
      item=line.split(Splitor) 

      while(True):
        if '' in item: 
          item.remove('')
        else:
          break

      for line in item:
        line=Splitor+line
        line=''.join(line.split())
        try:
          s_m=RE.search(line)
          if s_m:
            #lo.append(os.getenv('STARBLAZE_ENV')+'/'+s_m.group())
            if env_re.search(s_m.group()): 
              t_env_m =env_re.search(s_m.group())
              t_env=t_env_m.group()
              dirs=s_m.group().split('/') 
              dirs[0]=os.getenv(t_env)
              dir='/'.join(dirs)
              lo.append(dir)
            else: 
              lo.append(s_m.group())
          else:
            if option.Step:
              print info000+line
        except:
          lo=lo+line.split(Splitor)

def parser(option, TYPE0=REGRESSION, TYPE1=SESSION, TYPE2=GROUP, TYPE3=TEST, TYPE4=ATTRIBUTE):
  ''' parse the tdef info and construct the data base '''

  assert not ((option.TdefFiles != None) and (option.Tdeflist != None)), tdef001

  if option.TdefFiles == None:
    tdef=option.Tdeflist

  if tdef == None: 
    assert os.getenv('STARBLAZE_ENV')!=None, tdef000   

    tdef=os.getenv('STARBLAZE_ENV')+'/parser.rc'

  tdef_list=[]

  try:
    if option.TdefFiles == None:
      with open(tdef, 'r') as tdef:
        parser_rc_solver(tdef, tdef_list, include_re, '`include')  
    else:
      tdef_list.append(option.TdefFiles)
  except:
    print "Please check your parser.rc files : "+tdef
    assert False, tdef002
  finally:
    if option.Step:
      print info001

  parser_thread=[]
  sessions=[]

  for t in tdef_list:
    parser_args=[]
    parsethread=THREAD(t, SESSION, option)
    parser_args.append(option)
    parser_args.append(t)
    parser_args.append(sessions)
  
    @parsethread.register(name='return paring : '+t, args=parser_args)
    def get_data_structure(option, file, lo, TYPE1=SESSION, TYPE2=GROUP, TYPE3=TEST, TYPE4=ATTRIBUTE):
      ''' construct the data structure'''
      #if True:
      try:
        with open(file, 'r') as ParseFile:
          if option.Step:
            print info002+file
          construct_data_structure(option, ParseFile, lo)
      except: 
        print "Please check your tdef files : "+file
        assert False,tdef003 
      finally:
        if option.Step:
          print info003+file
      return lo[0]



    parsethread.setDaemon(True)
    parser_thread.append(parsethread)

  for i in parser_thread: 
    i.start()

  parser_thread_num = len(parser_thread)

  while(True):
    for i in  parser_thread: 
      if i.Stop_Thread:
        p=i.stop()
        sessions.append(p)
        parser_thread.remove(i)

        if option.Step:
          print info004+i.Name


    if len(parser_thread)==0 and (len(sessions) ==  parser_thread_num):

      if option.Step:
        print info005
      break
  # May use time sleep to reduce CPU IPC cost, but it not the critical cost  

  #time.sleep(5)

  # naming clash judgement  
  session_naming_clash=[]
  o=TYPE0()
  o.sessions={}

  for i in sessions:
    if i.name not in session_naming_clash:
      session_naming_clash.append(i.name) 
      o.sessions[i.name]=copy.deepcopy(i)
    else: 
      assert False, tdef005+i.sessionname

  return o

######################################################################################################
#                                            Searcher    
######################################################################################################
#                              Search valid testcase for regression
##################################################
#              Classify Function
##################################################
def classify_engine(option, s, t):
 
  ''' the basic classify function'''

  assert option.VENDOR in EDA_Vendor_List, tdef036

  if option.VENDOR == 'synopsys':
    if (synopsys_cmd_pre[s.name] != None or synopsys_cmd_post[s.name] != None):
      if synopsys_cmd_pre[s.name] != None or synopsys_cmd_post[s.name] != None:
        value = synopsys_cmd_pre[s.name]+s.value

      if synopsys_cmd_post[s.name] != None: 
        value = value+synopsys_cmd_post[s.name]
    else:
      value = s.value
  elif option.VENDOR == 'cadence':
    if (cadence_cmd_pre[s.name] != None or cadence_cmd_post[s.name] != None):
      if cadence_cmd_pre[s.name] != None or cadence_cmd_post[s.name] != None:
        value = cadence_cmd_pre[s.name]+s.value

      if cadence_cmd_post[s.name] != None: 
        value = value+cadence_cmd_post[s.name]
    else:
      value = s.value
  elif option.VENDOR == 'mentor':
    if (mentor_cmd_pre[s.name] != None or mentor_cmd_post[s.name] != None):
      if mentor_cmd_pre[s.name] != None or mentor_cmd_post[s.name] != None:
        value = mentor_cmd_pre[s.name]+s.value

      if mentor_cmd_post[s.name] != None: 
        value = value+mentor_cmd_post[s.name]
    else:
      value = s.value

  while(env_re.search(value)):
    env_m=env_re.search(value)
    env = env_m.group()
    assert os.getenv(env) != None, tdef037+env  
    value=value.replace('${'+env+'}', os.getenv(env))

  if (s.attr == 'add') and add_options[s.name]:
    t.attributes[attribute_type[s.name]][s.name].append(value)
  elif s.attr == 'remove' and add_options[s.name]:
    if value in t.attributes[attribute_type[s.name]][s.name]:
      t.attributes[attribute_type[s.name]][s.name].remove(value)
  elif s.attr == 'assign':
    if not add_options[s.name]:
      t.attributes[attribute_type[s.name]][s.name] = []

    t.attributes[attribute_type[s.name]][s.name].append(value)

  elif s.attr == 'override':
    t.attributes[attribute_type[s.name]][s.name] = []
    t.attributes[attribute_type[s.name]][s.name].append(value)



def init_test_attr_dict(TYPE=TESTCASE):

  t=TYPE()

  t.attributes ={}

  for i in optype_list:
    t.attributes[i] = {}

  for i in attribute_type.keys():
    t.attributes[attribute_type[i]][i] = []

  return t 

def argsparser(test, option):
  assert isinstance(test, TESTCASE), tdef037 

  cmd_json_obj = TestEncoder().encode(option)
  cmd_dict = json.loads(cmd_json_obj)

  for i in attr_cmdline_map_dict.keys():

    if cmd_dict[i] != None:
      if i not in cmd_line_plus:
        test.attributes[attribute_type[attr_cmdline_map_dict[i]]][attr_cmdline_map_dict[i]]=[]
      else:
        pass

      test.attributes[attribute_type[attr_cmdline_map_dict[i]]][attr_cmdline_map_dict[i]].append(cmd_dict[i])

  #give default value to attribute which no define in tdef
  for i in attr_default_dict.keys():
    if len(test.attributes[attribute_type[i]][i]) == 0:
      if i in attr_relation_dict.keys():
        if len(test.attributes[attribute_type[attr_relation_dict[i]]][attr_relation_dict[i]]) != 0:
          test.attributes[attribute_type[i]][i].append(\
          attr_default_dict[i][test.attributes[attribute_type[attr_relation_dict[i]]][attr_relation_dict[i]][0]])
        else:
          test.attributes[attribute_type[i]][i].append(\
          attr_default_dict[i][attr_default_dict[attr_relation_dict[i]]])
      else:
        test.attributes[attribute_type[i]][i] = attr_default_dict[i]
    else:
      pass

def find_a_test(option, d, regression, lo, TYPE=TESTCASE):
  
  # check the whether the test belong to specific category
  if (d.groups[regression[1]].tests[regression[2]].category == None) or (option.CATEGORY == None) or \
     (option.CATEGORY in d.groups[regression[1]].tests[regression[2]].category):  

    t=init_test_attr_dict(TYPE)

    if hasattr(d, 'attributes'): 
      for i in d.attributes:
        classify_engine(option, i, t) 

    assert regression[1] in d.groups, tdef034+regression[1] 

    if hasattr(d.groups[regression[1]], 'attributes'): 
      for i in d.groups[regression[1]].attributes:
        classify_engine(option, i, t) 

    assert regression[2] in d.groups[regression[1]].tests, tdef035+regression[2] 

    if hasattr(d.groups[regression[1]].tests[regression[2]], 'attributes'): 
      for i in d.groups[regression[1]].tests[regression[2]].attributes:
        classify_engine(option, i, t) 

    t.testname=regression[2]
    t.sessionname=regression[0]
    t.groupname=regression[1]

    # add Command line to 
    argsparser(t, option)

    lo.append(t)
  else:
    pass

def find_all_group_test(option, d, regression, lo, TYPE=TESTCASE):

  # find all test name in groups
  for i in d.groups[regression[1]].tests:  
    regression_t=[]
    regression_t = copy.deepcopy(regression)
    regression_t.append(i)

    find_a_test(option, d, regression_t, lo, TYPE)

def find_all_session_test(option, d, regression, lo, TYPE=TESTCASE):

  # find all test name in groups
  for i in d.groups:
    for j in d.groups[i].tests:
      regression_t=[]
      regression_t = copy.deepcopy(regression)
      regression_t.extend([i,j])

      find_a_test(option, d, regression_t, lo, TYPE)


find_tests = {
    'TEST'    : lambda option, d, regression, lo, TYPE: find_a_test(option, d, regression, lo, TYPE), 
    'GROUP'   : lambda option, d, regression, lo, TYPE: find_all_group_test(option, d, regression, lo, TYPE),
    'SESSION' : lambda option, d, regression, lo, TYPE: find_all_session_test(option, d, regression, lo, TYPE)
}


def search_cfg(option, d, regression, lo, TYPE=TESTCASE):
  '''
  search attibutes store in database
  '''
  assert isinstance(d, SESSION), tdef032  

  num=len(regression)

  optype = len(regression) == 3 and 'TEST' or (len(regression) == 2 and 'GROUP' or 'SESSION') 

  find_tests[optype](option, d, regression, lo, TYPE)

def print_full_test_path(testpath):

  assert type(testpath) == list, tdef033

  string=''
  for i in range(0, len(testpath)):
    if testpath[i] != 'GROUP':
      string= i != 0 and string+'/'+testpath[i] or testpath[i]
  return string

def find_session(data, regression):
  ''' find valid session object by name'''

  # updated for single name search 
  if regression[0] in data.sessions:
     o = data.sessions[regression[0]]
     pre_regression = regression
  else: 
    naming_clash = False
    find_test={}
    pre_regression = []
    for i in data.sessions:
      if regression[0] in data.sessions[i].groups:  
        # groups name check
        if naming_clash:
          print 'there are two groups with same name : '
          print ' 1. Session : '+o.name+' Group : '+regression[0]
          print ' 2. Session : '+i+' Group : '+regression[0]
          assert False,  'Please check the details'
        else:
          o=data.sessions[i]
          pre_regression.append(i)
          pre_regression.extend(regression)
          naming_clash = True
      elif regression[0] in data.sessions[i].testpath: 
        # test name check

        #a single name as a test name in different sessions    
        if regression[0] in find_test.keys(): 
          print '\033[31;1m there are two test with same name in different session: \033[0m'
          print '1. '+find_test[regression[0]]
          for i in range(0, len(data.sessions[i].testpath[regression[0]])):
            full_path=print_full_test_path(data.sessions[i].testpath[regression[0]][i])
            print str(i+2)+'. '+full_path
          assert False, tdef040

        #a single name as a test name in different groups of a same session    
        if len(data.sessions[i].testpath[regression[0]]) != 1:
          print "\033[31;1m there are more than one test with name as "+regression[0]+'\033[0m'
          for j in range(0, len(data.sessions[i].testpath[regression[0]])):
            full_path=print_full_test_path(data.sessions[i].testpath[regression[0]][j])
            if j==0: 
              print '**************************************************'
            print str(j+1)+'. '+full_path
            if j==len(data.sessions[i].testpath[regression[0]])-1:
              print '**************************************************'
          assert False, tdef040

        find_test[regression[0]]= data.sessions[i].testpath[regression[0]]
        
        o=data.sessions[i]
        
        pre_regression=copy.deepcopy(data.sessions[i].testpath[regression[0]][0])

  regression = copy.deepcopy(pre_regression)

  assert isinstance(o, SESSION), tdef032

  return o, regression

def searcher(option, data):

  ''' search test info by RegressName '''

  lo = []
  RegressName = option.Test

  assert isinstance(data, REGRESSION), tdef029 

  regression = "/" in RegressName and  ''.join(RegressName).split(r"/") or [RegressName] 
  
  regression='' in regression and regression.remove('') or regression

  assert len(regression)<=3,tdef030+RegressName

  o, regression=find_session(data, regression)

  search_cfg(option, o, regression, lo)

  return lo

def lister(option, o, OpPipe, lsf_queue):
  pre_session=None
  pre_group=None

  print info010

  for i in o.sessions:
    for j in o.sessions[i].groups:
      for k in o.sessions[i].groups[j].tests: 
        if i != pre_session:
          print "\nSESSION : "+i
          pre_session = i
        if j != pre_group:
          print "\n  GORUP : "+j
          pre_group = j

        if o.sessions[i].groups[j].tests[k].category == None:
          category = ''
        else:
          category = '    category :  '+o.sessions[i].groups[j].tests[k].category

        print "    TEST : "+k+category

def debugger(lo):
  for i in lo:
    item=TestEncoder().encode(i) 
    if not i.groupname == None:
      print i.sessionname+'/'+i.groupname+'/'+i.testname
    else:
      print i.sessionname+'/'+i.testname

    print item



      

